/*
 * Middleware
 * Copyright (C) 2010/11
 * Riccardo Pulvirenti, Giuseppe Ravidà, Andrea Tino
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANDABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see http://www.gnu.org/licenses
 */

/*!
 * File: ui.cpp
 */

#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <boost/lexical_cast.hpp>
#include <boost/thread.hpp>

#include "ui.hpp"
#include "wfqueue_proxy_factory.hpp"
#include "task_descriptor.hpp"
#include "utils.hpp"

using namespace middleware;

//-----------------------------------------------------------------------------
// Constructors and destructor
/* Default constructor */
UI::UI() {
	this->_config.ui_ip_toman = "127.0.0.1";
	this->_config.ui_port_toman = "0";
	this->_config.ui_port_tow_bind = this->createPort();
	this->_config.ui_ip_tow_bind = "127.0.0.1"; /* Not used to bind */
}
/* Constructor with configuration */
UI::UI(UIConfig conf) {
	this->_config.ui_ip_toman = conf.ui_ip_toman;
	this->_config.ui_port_toman = conf.ui_port_toman;
	this->_config.ui_port_tow_bind = conf.ui_port_tow_bind;
	this->_config.ui_ip_tow_bind = conf.ui_ip_tow_bind; /* Not used to bind */
}
/* Destructor */
UI::~UI() {

}
//-----------------------------------------------------------------------------
// Private members
/* Gets a random port */
std::string UI::createPort() {
	return utils::GetRandomIntegralNumberStr(kUIMinManPort, kUIMaxManPort);
}
/* Sending workflow */
Workflow* UI::CreateWorkflow() {
	// Generate a random taskDescriptor set
	int ntask;
	std::vector<TaskDescriptor> tasks;
	Workflow* wf = new Workflow;
	TaskLinkage link;
	ntask = utils::GetRandomIntegralNumberInt(1, kUIMaxTasksInWorkflow);
	for (int i = 0; i < ntask; i++) {
		std::ostringstream stask;
		TaskDescriptor task;
		stask << "Task-" << i;
		task.set_type((i % 2) == 0 ? kTaskExecutable : kTaskBashCommand);
		task.set_command("command_" + stask.str());
		link.machine_addr = "/home";
		link.network_inet_ip = "127.0.0.1";
		link.network_inet_port = "1024";
		task.set_link(link);
		tasks.push_back(task); /* Inserting task */
	}
	wf->assign(tasks.begin(), tasks.end()); /* Assigning tasks */
	// Return workflow
	return wf;
}
/* Thread execution flow */
void UI::exec() {
	std::cout << kUIEtq << "Running!" << std::endl;
	try {
		this->bonjour(); /* Initialization sequence */
		// Creating proxy to communicate to Manager
		std::cout << kUIEtq << "Configuring proxy factory..." << std::endl;
		WFQueueProxyFactory proxy_factory(this->_config.ui_ip_toman,
				this->_config.ui_port_toman);
		std::cout << kUIEtq << "Proxy factory configured: Ip=" <<
				this->_config.ui_ip_toman << " and Port=" <<
				this->_config.ui_port_toman << "!" << std::endl;
		std::cout << kUIEtq << "Getting proxy from factory..." << std::endl;
		// Dynamic allocating proxy
		WFQueueManagerProxy* proxy = proxy_factory.getProxy(); /* Got proxy */
		std::cout << kUIEtq << "Got proxy!" << std::endl;
		std::cout << kUIEtq << "Entering workflow random generation loop..." <<
				std::endl;
		// Sending workflows randomly
		for (;;) {
			unsigned int waiter = (utils::GetRandomIntegralNumberInt(1,
					kUIMaxWorkflowGeneretionPeriod) * 1000);
			Workflow* wf = this->CreateWorkflow();
			std::cout << kUIEtq << "Created WF: " << wf->get_id() <<
					" having " << wf->size() << " tasks!" << std::endl;
			// Send workflow
			proxy->enqueue(*wf);
			std::cout << kUIEtq << "Sent WF: " << wf->get_id() << " (" <<
					wf->size() << " tasks)!" << std::endl;
			delete wf; /* Clearing */
			std::cout << kUIEtq << "Reactivating loop after " << waiter <<
					" msecs..." << std::endl;
			// Sleeping a random interval
			boost::this_thread::sleep(boost::posix_time::milliseconds(waiter));
		}
	} catch(GenericException& e) {
		/* Proxy reference is automatically destroys as the factory gets
		 * out of scope */
		std::cout << kUIEtq << "Error: " << e.what() << std::endl;
		std::cout << kUIEtq << "Now exiting!" << std::endl;
	} catch(std::exception& e) {
		/* Proxy reference is automatically destroys as the factory gets
		 * out of scope */
		std::cout << kUIEtq << "Error: " << e.what() << std::endl;
		std::cout << kUIEtq << "Now exiting!" << std::endl;
	}
}
/* Thread execution flow for data requests acceptor */
void UI::exec_data_requests() {
	std::cout << kUIEtq << kUI1Etq << "Running!" << std::endl;
}
/* Bonjour */
void UI::bonjour() throw(GenericException) {
	std::cout << kUIEtq << "Initialization sequence now started..." <<
			std::endl;
	std::cout << kUIEtq << "Configuration loaded: bind_towIP: this, " <<
			"bind_towPORT:" << this->_config.ui_port_tow_bind << " tomanIP: " <<
			this->_config.ui_ip_toman << ", tomanPORT: " <<
			this->_config.ui_port_toman << std::endl;
	if (this->_config.ui_port_toman == "0")
		throw GenericException("Invalid connection to Manager parameters provided!");
	std::cout << kUIEtq << "Initialization completed!" << std::endl;
}
